﻿using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TL_Cloud.API.Helpers;
using TL_Cloud.Core.Entities;
using TL_Cloud.Core.Extensions;
using TL_Cloud.Core.Interfaces;
using TL_Cloud.Core.LinkURL;
using TL_Cloud.Core.Services;
using TL_Cloud.Models.BookShop;
using TL_Cloud.RepositoryInterface.BookShop;
using TL_Cloud.ViewModels.BookShop.BaseStudent;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace TL_Cloud.API.Controllers
{
    /// <summary>
    /// 学生信息
    /// </summary>
    //[Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class StudentsController : Controller
    {
        private readonly ILogger logger;
        private readonly IUnitOfWork _unitOfWork;
        private readonly IBaseStudentRepository _studentRepository;
        private readonly ITypeHelperService _typeHelperService;
        private readonly IPropertyMappingContainer _propertyMappingContainer = null;
        private readonly IMapper _mapper;
        private readonly IUrlHelper _urlHelper;

        public StudentsController(IMapper mapper,
            ILogger<StudentsController> logger,
            ITypeHelperService typeHelperService,
            IPropertyMappingContainer propertyMappingContainer,
            IBaseStudentRepository studentRepository,
            IUnitOfWork unitOfWork,
            IUrlHelper urlHelper
            )
        {
            this._mapper = mapper;
            this.logger = logger;
            this._typeHelperService = typeHelperService;
            this._studentRepository = studentRepository;
            this._urlHelper = urlHelper;
            this._propertyMappingContainer = propertyMappingContainer;
            this._unitOfWork = unitOfWork;
        }
        /// <summary>
        /// 获取学生信息
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        [HttpGet(Name = "GetStudents")]
        public async Task<IActionResult> Get([FromQuery]BaseStudentQueryParameters parameters)
        {

            //判断排序是否存在 ，
            if (!_propertyMappingContainer.ValidateMappingExistsFor<BaseStudentResource, Base_StudentInfo>(parameters.OrderBy))
            {
                return BadRequest("Can't finds fields for sorting.");
            }

            //判断fields参数是否在制定的类型中存在
            if (!_typeHelperService.TypeHasProperties<BaseStudentResource>(parameters.Fields))
            {
                return BadRequest("Fields not exist.");
            }

            var dataList = await _studentRepository.GetAllEntitiesAsync(parameters);

            var StudentResources = _mapper.Map<IEnumerable<Base_StudentInfo>, IEnumerable<BaseStudentResource>>(dataList);

            //生成 下一个连接和上一个连接的url
            var previousPageLink = dataList.HasPrevious ?
                new LinkUrlCreater<BaseStudentQueryParameters>(_urlHelper).CreateGetUrl("GetStudents", parameters,
                    PaginationResourceUriType.PreviousPage) : null;

            var nextPageLink = dataList.HasNext ?
               new LinkUrlCreater<BaseStudentQueryParameters>(_urlHelper).CreateGetUrl("GetStudents", parameters,
                    PaginationResourceUriType.NextPage) : null;


            //数据返回分页数据
            var meta = new
            {
                dataList.TotalItemsCount,
                dataList.PageSize,
                dataList.PageIndex,
                dataList.PageCount,
                previousPageLink,
                nextPageLink
            };

            Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(meta, new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));
            //返回结果塑性
            return Ok(StudentResources.ToDynamicIEnumerable(parameters.Fields));
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        [HttpGet("{id}", Name = "GetStudent")]
        public async Task<IActionResult> Get(string id, string fields = null)
        {
            if (!_typeHelperService.TypeHasProperties<BaseStudentResource>(fields))
            {
                return BadRequest("Fields not exist.");
            }
            var Student = await _studentRepository.GetEntityByIdAsync(id);

            if (Student == null)
            {
                return NotFound();
            }

            var StudentResource = _mapper.Map<Base_StudentInfo, BaseStudentResource>(Student);
            var shapedStudentResource = StudentResource.ToDynamic(fields);
            var links = new LinkUrlCreater<BaseStudentQueryParameters>(_urlHelper).CreateLinksForPost("GetStudent", "DeleteStudent", id, fields);
            var result = (IDictionary<string, object>)shapedStudentResource;
            result.Add("links", links);

            return Ok(result);
        }

        /// <summary>
        /// 增加数据
        /// </summary>
        /// <param name="value"></param>
        [HttpPost(Name = "CreateStudent")]
        public async Task<IActionResult> Post([FromBody] BaseStudentBasicInfoResource studentAddResource)
        {
            if (studentAddResource == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var userInfo = this.GetUserInfo();

            var newTeacher = _mapper.Map<BaseStudentBasicInfoResource, Base_StudentInfo>(studentAddResource);
            newTeacher.Create(userInfo.Item1,userInfo.Item2);

            _studentRepository.Add(newTeacher);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception("Save Failed!");
            }

            var resultResource = _mapper.Map<Base_StudentInfo, BaseStudentResource>(newTeacher);

            var links = new LinkUrlCreater<BaseStudentQueryParameters>(_urlHelper).CreateLinksForPost("GetStudent", "DeleteStudent", newTeacher.StudentId);
            var linkedPostResource = resultResource.ToDynamic() as IDictionary<string, object>;
            linkedPostResource.Add("links", links);
            return CreatedAtRoute("GetStudent", new { id = linkedPostResource["StudentId"] }, linkedPostResource);
        }

        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="id"></param> 
        [HttpPut("{id}", Name = "UpdateStudent")]
        public async Task<IActionResult> Update(string id, [FromBody] BaseStudentUpdateResource studentUpdate)
        {
            if (studentUpdate == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var teacher = await _studentRepository.GetEntityByIdAsync(id);
            if (teacher == null)
            {
                return NotFound();
            }
            var userInfo = this.GetUserInfo();
            _mapper.Map(studentUpdate, teacher);
            teacher.Modify(userInfo.Item1, userInfo.Item2);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Updating Student {id} failed when saving.");
            }
            return NoContent();
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}", Name = "DeleteStudent")]
        public async Task<IActionResult> DeleteStudent(string id)
        {
            var post = await _studentRepository.GetEntityByIdAsync(id);
            if (post == null)
            {
                return NotFound();
            }
            _studentRepository.Delete(post);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Deleting Student {id} failed when saving.");
            }

            return NoContent();
        }
    }
}
